<template>
  <div class="app-container">
    <div class="search-bar">
      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
        <el-form-item prop="roleName" :label="$t('common.keywords')">
          <el-input
            v-model="queryParams.roleName"
            :placeholder="$t('role.name')"
            clearable
            @keyup.enter="handleQuery"
          />
        </el-form-item>
        <el-form-item prop="roleStatus" :label="$t('common.showStatus')">
          <el-select
            v-model="queryParams.roleStatus"
            :placeholder="$t('common.choose')"
            :no-match-text="$t('common.choose')"
            style="width: 300px"
            @change="handleQuery"
          >
            <el-option
              v-for="item in roleStatusOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="search" @click="handleQuery">
            {{ $t("common.search") }}
          </el-button>
          <el-button icon="refresh" @click="handleResetQuery">{{ $t("common.reset") }}</el-button>
        </el-form-item>
      </el-form>
    </div>

    <el-card shadow="never">
      <div class="mb-10px">
        <el-button
          v-hasPerm="'sys:role:add'"
          type="success"
          icon="plus"
          @click="handleOpenDialog(0)"
        >
          {{ $t("common.add") }}
        </el-button>
        <el-button
          v-hasPerm="'sys:role:delete'"
          type="danger"
          :disabled="ids.length === 0"
          icon="delete"
          @click="handleDelete()"
        >
          {{ $t("common.delete") }}
        </el-button>
      </div>

      <el-table
        ref="dataTableRef"
        v-loading="loading"
        :data="roleList"
        highlight-current-row
        stripe
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column :label="$t('role.name')" prop="roleName" min-width="100" />
        <el-table-column :label="$t('solution.name')" prop="solutionId">
          <template #default="scope">
            {{ solutionOptions.get(scope.row.solutionId) }}
          </template>
        </el-table-column>
        <el-table-column :label="$t('user.userType')" prop="userType">
          <template #default="scope">
            {{ userTypeMap.get(scope.row.userType) }}
          </template>
        </el-table-column>
        <el-table-column :label="$t('common.remark')" prop="remark" />
        <el-table-column :label="$t('common.showStatus')" align="center" width="100">
          <template #default="scope">
            <el-tag v-if="scope.row.roleStatus === 1" type="success">
              {{ $t("common.status.enable") }}
            </el-tag>
            <el-tag v-else-if="scope.row.roleStatus === -1" type="danger">
              {{ $t("common.status.disable") }}
            </el-tag>
            <el-tag v-else type="info">{{ $t("common.status.unEnable") }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column fixed="right" :label="$t('common.action')" width="220">
          <template #default="scope">
            <el-button
              v-hasPerm="'sys:role:setperms'"
              type="primary"
              size="small"
              link
              icon="position"
              @click="handleOpenAssignPermDialog(scope.row)"
            >
              {{ $t("role.menus") }}
            </el-button>
            <el-button
              v-hasPerm="'sys:role:edit'"
              type="primary"
              size="small"
              link
              icon="edit"
              @click="handleOpenDialog(scope.row.roleId)"
            >
              {{ $t("common.edit") }}
            </el-button>
            <el-button
              v-hasPerm="'sys:role:delete'"
              type="danger"
              size="small"
              link
              icon="delete"
              @click="handleDelete(scope.row.roleId)"
            >
              {{ $t("common.delete") }}
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <pagination
        v-if="total > 0"
        v-model:total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="handleQuery"
      />
    </el-card>

    <el-dialog
      v-model="dialog.visible"
      :title="dialog.title"
      width="500px"
      @close="handleCloseDialog"
    >
      <el-form ref="roleFormRef" :model="formData" :rules="rules">
        <el-form-item :label="$t('role.name')" prop="roleName">
          <el-input
            v-model="formData.roleName"
            :placeholder="$t('common.choose') + $t('role.name')"
          />
        </el-form-item>
        <el-form-item :label="$t('role.childRoles')" prop="visiableRoleIds">
          <el-select
            v-model="formData.formVisiableRoleIds"
            multiple
            :placeholder="$t('common.choose') + $t('role.childRoles')"
            :no-match-text="$t('common.choose') + $t('role.childRoles')"
            style="width: 240px"
          >
            <el-option
              v-for="item in visiableRoleIdsOptions"
              :key="item.roleId"
              :label="
                item.roleName +
                (item.remark != null && item.remark != '' ? '(' + item.remark + ')' : '')
              "
              :value="item.roleId + ''"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('role.mapRoleId')" prop="mapRoleId">
          <el-select
            v-model="formData.mapRoleId"
            :placeholder="$t('common.choose') + $t('role.mapRoleId')"
            :no-match-text="$t('common.choose') + $t('role.mapRoleId')"
            style="width: 240px"
          >
            <el-option
              v-for="item in visiableRoleIdsOptions"
              :key="item.roleId"
              :label="
                item.roleName +
                (item.remark != null && item.remark != '' ? '(' + item.remark + ')' : '')
              "
              :value="Number(item.roleId)"
            />
          </el-select>
          <el-tooltip
            style="margin-left: 10px"
            class="box-item"
            effect="dark"
            :content="$t('role.mapRoleIdTip')"
            placement="top-start"
          >
            <el-icon><InfoFilled /></el-icon>
          </el-tooltip>
        </el-form-item>
        <el-form-item :label="$t('solution.name')" prop="solutionId">
          <el-select
            v-model="formData.solutionId"
            :placeholder="$t('common.plsChoose') + $t('solution.name')"
            :no-match-text="$t('common.plsChoose') + $t('solution.name')"
            style="width: 240px"
          >
            <el-option
              v-for="item in solutionOptionsArr"
              :key="item.id"
              :label="item.title"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('user.userType')" prop="userType">
          <el-select
            v-model="formData.userType"
            :no-match-text="$t('common.plsChoose')"
            :placeholder="$t('common.plsChoose')"
          >
            <el-option v-for="item in userTypeOptions" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('common.remark')" prop="remark">
          <el-input v-model="formData.remark" :placeholder="$t('common.remark')" />
        </el-form-item>
        <el-form-item :label="$t('common.showStatus')" prop="roleStatus">
          <el-radio-group v-model="formData.roleStatus">
            <el-radio :label="1">{{ $t("common.status.enable") }}</el-radio>
            <el-radio :label="0">{{ $t("common.status.unEnable") }}</el-radio>
            <el-radio :label="-1">{{ $t("common.status.disable") }}</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">{{ $t("common.confirm") }}</el-button>
          <el-button @click="handleCloseDialog">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-dialog>

    <el-drawer
      v-model="assignPermDialogVisible"
      :title="'【' + checkedRole.roleName + '】'"
      size="500"
    >
      <div class="flex-x-between">
        <el-input
          v-model="permKeywords"
          clearable
          class="w-[150px]"
          :placeholder="$t('role.permName')"
        >
          <template #prefix>
            <Search />
          </template>
        </el-input>

        <div class="flex-center ml-5">
          <el-button type="primary" size="small" plain @click="togglePermTree">
            <template #icon>
              <Switch />
            </template>
            {{ isExpanded ? $t("common.close1") : $t("common.open1") }}
          </el-button>
          <el-checkbox
            v-model="parentChildLinked"
            class="ml-5"
            @change="handleparentChildLinkedChange"
          >
            {{ $t("role.pareChild") }}
          </el-checkbox>

          <el-tooltip placement="bottom">
            <template #content>
              {{ $t("role.tip1") }}
            </template>
            <el-icon class="ml-1 color-[--el-color-primary] inline-block cursor-pointer">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
      </div>

      <el-tree
        ref="permTreeRef"
        node-key="value"
        show-checkbox
        :data="menuPermOptions"
        :filter-node-method="handlePermFilter"
        :default-expand-all="true"
        :check-strictly="!parentChildLinked"
        class="mt-5"
      >
        <template #default="{ data }">
          {{ data.label }}
        </template>
      </el-tree>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleAssignPermSubmit">
            {{ $t("common.confirm") }}
          </el-button>
          <el-button @click="assignPermDialogVisible = false">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<script setup lang="ts">
import { useI18n } from "vue-i18n";
const { t } = useI18n();
defineOptions({
  name: "Role",
  inheritAttrs: false,
});

import RoleAPI, { RolePageVO, RoleForm, RolePageQuery, RoleFormX } from "@/api/system/role";
import SolutionAPI from "@/api/solution/index";
import MenuAPI from "@/api/system/menu";
import UserAPI from "@/api/system/user";

const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm);
const permTreeRef = ref<InstanceType<typeof ElTree>>();
const roleFormX: RoleFormX = reactive({ roleIdsStr: "", roleList: [] });

const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const showRoleType = ref(false);

const solutionOptions = reactive(new Map<number, { title: string }>([]));
const solutionOptionsArr = ref<any[]>([]);

const queryParams = reactive<RolePageQuery>({
  pageNum: 1,
  pageSize: 10,
  roleName: "",
  roleStatus: 9,
});

const roleList = ref<RolePageVO[]>();
const menuPermOptions = ref<OptionType[]>([]);
const visiableRoleIdsOptions = ref<RolePageVO[]>([]);

const dialog = reactive({
  title: "",
  visible: false,
});

const formData = reactive<RoleForm>({
  roleId: 0,
  roleName: "",
  roleStatus: 1,
  roleType: 0,
  paidStatus: 0,
  formVisiableRoleIds: [],
  mapRoleId: undefined,
  solutionId: undefined,
  userType: 1,
  remark: "",
});

const rules = reactive({
  roleName: [{ required: true, message: t("common.plsInput") + t("role.name"), trigger: "blur" }],
  roleStatus: [
    { required: true, message: t("common.choose") + t("common.showStatus"), trigger: "blur" },
  ],
});

const roleStatusOptions = ref<OptionType[]>([
  {
    label: t("common.all"),
    value: 9,
  },
  {
    label: t("common.status.enable"),
    value: 1,
  },
  {
    label: t("common.status.unEnable"),
    value: 0,
  },
  {
    label: t("common.status.disable"),
    value: -1,
  },
]);

const userTypeOptions = [
  { label: t("user.userTypeOptions.1"), value: 1 },
  { label: t("user.userTypeOptions.2"), value: 2 },
  { label: t("user.userTypeOptions.5"), value: 5 },
  { label: t("user.userTypeOptions.10"), value: 10 },
];
const userTypeMap = new Map<number, string>([
  [1, t("user.userTypeOptions.1")],
  [2, t("user.userTypeOptions.2")],
  [5, t("user.userTypeOptions.5")],
  [10, t("user.userTypeOptions.10")],
]);

interface CheckedRole {
  roleId?: number;
  roleName?: string;
}
const checkedRole = ref<CheckedRole>({});
const assignPermDialogVisible = ref(false);

const permKeywords = ref("");
const isExpanded = ref(true);

const parentChildLinked = ref(true);

function handleQuery() {
  loading.value = true;
  RoleAPI.getPage(queryParams)
    .then((data) => {
      roleList.value = data.list;
      total.value = data.total;
    })
    .finally(() => {
      loading.value = false;
    });
}

function handleResetQuery() {
  queryFormRef.value.resetFields();
  queryParams.pageNum = 1;
  handleQuery();
}

function handleSelectionChange(selection: any) {
  ids.value = selection.map((item: any) => item.roleId);
}

function handleOpenDialog(roleId?: number) {
  dialog.visible = true;
  UserAPI.getProfile().then((data) => {
    if (data.userCustomerId > 0) {
      showRoleType.value = false;
    } else {
      showRoleType.value = true;
    }
  });

  RoleAPI.getAllRoles(roleId).then((res) => {
    Object.assign(roleFormX, res);
    if (roleFormX.roleIdsStr != null) {
      formData.formVisiableRoleIds = roleFormX.roleIdsStr.split(",");
      console.log(formData.formVisiableRoleIds);
      if (formData.mapRoleId == 0) {
        formData.mapRoleId = undefined;
      }
    }
    visiableRoleIdsOptions.value = roleFormX.roleList || [];
  });

  if (roleId) {
    dialog.title = t("common.edit");
    RoleAPI.getFormData(roleId).then((data) => {
      Object.assign(formData, data);
      if (formData.mapRoleId == 0) {
        formData.mapRoleId = undefined;
      }
      if (formData.solutionId == 0) {
        formData.solutionId = undefined;
      }
      if (formData.userType == 0) {
        formData.userType = 1;
      }
    });
  } else {
    dialog.title = t("common.add");
  }
}

function handleSubmit() {
  roleFormRef.value.validate((valid: any) => {
    if (valid) {
      loading.value = true;
      const roleId = formData.roleId;
      if (roleId) {
        RoleAPI.update(formData)
          .then((res) => {
            if (res.data.code === 200) {
              ElMessage.success(res.data.message);
              handleCloseDialog();
              handleResetQuery();
            } else {
              ElMessage.error(res.data.message);
            }
          })
          .finally(() => (loading.value = false));
      } else {
        RoleAPI.add(formData)
          .then((res) => {
            ElMessage.success(res.data.message);
            handleCloseDialog();
            handleResetQuery();
          })
          .finally(() => (loading.value = false));
      }
    }
  });
}

function handleCloseDialog() {
  dialog.visible = false;

  roleFormRef.value.resetFields();
  roleFormRef.value.clearValidate();

  formData.roleId = undefined;
  formData.roleStatus = 1;
  formData.roleName = "";
  formData.formVisiableRoleIds = [];
  formData.mapRoleId = undefined;
  formData.solutionId = undefined;
  formData.userType = 1;
  formData.remark = "";
  visiableRoleIdsOptions.value = [];
}

function handleDelete(roleId?: number) {
  const roleIds = [roleId || ids.value].join(",");
  if (!roleIds) {
    ElMessage.warning(t("common.plsChooseDeleteItem"));
    return;
  }

  ElMessageBox.confirm(t("common.confirmDelete"), t("common.warning"), {
    confirmButtonText: t("common.confirm"),
    cancelButtonText: t("common.cancel"),
    type: "warning",
  }).then(
    () => {
      loading.value = true;
      RoleAPI.deleteByIds(roleIds)
        .then((res) => {
          if (res.data.code === 200) {
            ElMessage.success(res.data.message);
            handleResetQuery();
          } else {
            ElMessage.error(res.data.message);
          }
        })
        .finally(() => (loading.value = false));
    },
    () => {
      ElMessage.info(t("common.cancelDelete"));
    }
  );
}

async function handleOpenAssignPermDialog(row: RolePageVO) {
  const roleId = row.roleId;
  if (roleId) {
    assignPermDialogVisible.value = true;
    loading.value = true;

    checkedRole.value.roleId = Number(roleId);
    checkedRole.value.roleName = row.roleName;

    menuPermOptions.value = await MenuAPI.getOptions();

    RoleAPI.getRoleMenuIds(checkedRole.value.roleId)
      .then((data) => {
        const checkedMenuIds = data;
        checkedMenuIds.forEach((menuId) => permTreeRef.value!.setChecked(menuId, true, false));
      })
      .finally(() => {
        loading.value = false;
      });
  }
}

function handleAssignPermSubmit() {
  const roleId = checkedRole.value.roleId;
  if (roleId) {
    const checkedMenuIds: number[] = permTreeRef
      .value!.getCheckedNodes(false, true)
      .map((node: any) => node.value);

    loading.value = true;
    let bindPermission: any = [];
    for (let i = 0; i < checkedMenuIds.length; i++) {
      bindPermission.push({
        roleId: roleId,
        permisId: checkedMenuIds[i],
      });
    }
    RoleAPI.updateRoleMenus(bindPermission)
      .then((res) => {
        if (res.data.code == 200) {
          ElMessage.success(res.data.message);
          assignPermDialogVisible.value = false;
          handleResetQuery();
        } else {
          ElMessage.error(res.data.message);
        }
      })
      .finally(() => {
        loading.value = false;
      });
  }
}

function togglePermTree() {
  isExpanded.value = !isExpanded.value;
  if (permTreeRef.value) {
    Object.values(permTreeRef.value.store.nodesMap).forEach((node: any) => {
      if (isExpanded.value) {
        node.expand();
      } else {
        node.collapse();
      }
    });
  }
}

watch(permKeywords, (val) => {
  permTreeRef.value!.filter(val);
});

function handlePermFilter(
  value: string,
  data: {
    [key: string]: any;
  }
) {
  if (!value) return true;
  return data.label.includes(value);
}

function handleparentChildLinkedChange(val: any) {
  parentChildLinked.value = val;
}

function getSolutionOptions() {
  SolutionAPI.getList({ pageNum: 1, pageSize: 1000 })
    .then((data) => {
      solutionOptionsArr.value = data.list;
      data.list.forEach((item: any) => {
        solutionOptions.set(item.id, item.title);
      });
    })
    .finally(() => {
      loading.value = false;
    });
}

onMounted(() => {
  getSolutionOptions();
  handleQuery();
});
</script>
